/*
 * Copyright 2002-2016 the atnoce.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.atnoce.onepass.view;

import com.atnoce.onepass.Start;
import com.atnoce.onepass.core.BackService;
import com.atnoce.onepass.core.SecurityController;
import com.atnoce.onepass.dao.CommonDao;
import com.atnoce.onepass.dao.OnepassConfigDao;
import com.atnoce.onepass.dao.PasswordItemDao;
import com.atnoce.onepass.net.BasicNetService;
import com.atnoce.onepass.pojo.OnepassConfig;
import com.atnoce.onepass.pojo.PasswordItem;
import com.atnoce.onepass.utils.*;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.controls.JFXToggleButton;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Pair;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author atnoce.com
 * @date 2016/11/6
 * @since 1.0.0
 */
public class PreferencesLayoutController {
    private Start start;
    private Stage preferencesDialogStage;
    private final OnepassConfigDao cd=new OnepassConfigDao();
    private final PasswordItemDao pd=new PasswordItemDao();
    public void setStart(Start start){
        this.start=start;
    }
    public void setPreferencesDialogStage(Stage preferencesDialogStage){
        this.preferencesDialogStage=preferencesDialogStage;
    }

    //---安全配置
    @FXML
    private ChoiceBox<Integer> jiaMiNum;
    @FXML
    private ImageView helpImg;
    @FXML
    private Button savePassGenerConfigBtn;
    @FXML
    private JFXButton changeMainPassBtn;
    //--常规配置
    @FXML
    private CheckBox startAutoUpdate;
    @FXML
    private JFXToggleButton minSysTuoPan;
    @FXML
    private JFXToggleButton closeMinWindowNoClose;
    @FXML
    private JFXToggleButton autoClearPanel;
    @FXML
    private ChoiceBox<String> autoClearPanelTime;
    @FXML
    private JFXToggleButton minningLock;
    @FXML
    private JFXToggleButton kongXianLock;
    @FXML
    private ChoiceBox<String> kongXianLockTime;
    @FXML
    private JFXButton saveChangGuiBtn;

    @FXML
    private TabPane tablePanel;

    //云服务
    @FXML
    private Label topLabel;
    @FXML
    private Label userNameLabel;
    @FXML
    private JFXTextField coludAccountInput;
    @FXML
    private JFXButton regBtn;
    @FXML
    private HBox regHboxPanel;
    @FXML
    private HBox timeServerHboxPanel;
    @FXML
    private JFXButton testLinkBtn;
    @FXML
    private JFXTextField serverAddress;
    @FXML
    private JFXTextField timeServerAddress;
    @FXML
    private JFXButton userTimeServerAddressBtn;

    @FXML
    private void initialize(){
        tablePanel.getSelectionModel().selectedItemProperty().addListener(
                (observable,oldValue,newValue)->{
                    String text = newValue.getText();
                    if(StringUtils.equals("安全", text)){

                    }else if(StringUtils.equals("常规", text)){
                        initChangGuiConfig(newValue);
                    }else if(StringUtils.equals("云服务", text)){
                        if(Boolean.valueOf(Cache.getProConfig(Const.ACTIONCLOUD))){
                            try {
                                topLabel.setText("已绑定账号:"+ SecurityController.getSecurityInstence().decryptColudAccount(Cache.getProConfig(Const.COLUDACCOUNT),Cache.getKey()));
                            } catch (Exception ex) {
                                CommonUtil.alert(Alert.AlertType.ERROR,"读取云账号出错！","错误详情："+ex.getMessage(),"错误").showAndWait();
                            }
                            topLabel.setTextFill(Color.web("#008000"));
                            //regHboxPanel.setDisable(true);

                            coludAccountInput.visibleProperty().bind(userNameLabel.visibleProperty());
                            regBtn.visibleProperty().bind(coludAccountInput.visibleProperty());
                            userNameLabel.visibleProperty().setValue(false);

                            timeServerHboxPanel.setDisable(false);

                            if (StringUtils.isNotEmpty(Cache.getProConfig(Const.TIMESERVER))){
                                timeServerAddress.setText(Cache.getProConfig(Const.TIMESERVER));
                            }
                            //regHboxPanel.setVisible(false);
                        }
                        if (StringUtils.isNotEmpty(Cache.getProConfig(Const.BASE_SERVER_ADDR))){
                            serverAddress.setText(Cache.getProConfig(Const.BASE_SERVER_ADDR));
                        }


                    }

                });
        saveChangGuiBtn.setOnAction(e->saveChangGuiBtnHandler());
        initChangGuiConfig(tablePanel.getSelectionModel().getSelectedItem());

        regBtn.setOnAction(e->regColud());

        changeMainPassBtn.setOnAction(e->changeMainPassBtnHandler());
        coludAccountInput.textProperty().addListener((observable,oldValue,newValue)->{
            regBtn.setDisable(newValue.trim().isEmpty());
        });
        testLinkBtn.setOnAction(e->testLinkHandler());
        userTimeServerAddressBtn.setOnAction(e->userTimeServerHandler());
    }

    private void userTimeServerHandler() {
        String addr = timeServerAddress.getText().trim();
        if (StringUtils.isEmpty(addr)){
            CommonUtil.alert(Alert.AlertType.ERROR,"测试失败！","服务器地址不能为空!","错误").show();
            return;
        }else if (addr.startsWith("http:")){
            CommonUtil.alert(Alert.AlertType.ERROR,"地址格式错误！","地址格式为：www.atnoce.com 请修改后重试!","错误").show();
            return;
        }else if (StringUtils.contains(addr,"qq.com")||StringUtils.contains(addr,"baidu.com")){
            CommonUtil.alert(Alert.AlertType.ERROR,"授时服务器设置失败！","请不要选用百度或腾讯作为授时服务器!","错误").show();
            return;
        }
        CommonUtil.alert(Alert.AlertType.INFORMATION,null,"设置授时服务器根据网络状况不同所需时间不同，系统大概需要10秒左右才可以完成校时，" +
                "在此期间请勿进行其他操作！\n点击确定按钮开始设置！","提示").showAndWait();
        Map<String, Object> map = BasicNetService.getInstance().testAndSetTimerServer("http://"+addr);
        if ((boolean)map.get("flag")){
            //测试成功，可以使用
            try {
                CommonUtil.alert(Alert.AlertType.INFORMATION,null,"已成功将授时服务器设置为: "+addr,"成功").show();
                InitContext.updateProperties("TIMESERVER",addr);
            } catch (IOException e) {
                CommonUtil.alert(Alert.AlertType.ERROR,"更新配置文件出错！","授时服务器可用，但是更新配置文件时出现错误： "+e.getMessage(),"错误").show();
                e.printStackTrace();
            }
        }else{
            CommonUtil.alert(Alert.AlertType.ERROR,"授时服务器设置失败！","设置授时服务器时发生错误: "+map.get("msg"),"错误").show();
        }

    }

    private void testLinkHandler() {
        String addr=serverAddress.getText().trim();
        Alert alert=null;
        if (addr.isEmpty()){
            CommonUtil.alert(Alert.AlertType.ERROR,"测试失败！","服务器地址不能为空!","错误").show();
            return;
        }else if(addr.startsWith("http://")){
            CommonUtil.alert(Alert.AlertType.ERROR,"测试失败！","服务器地址不能包含http,请直接填写域名或者IP部分!","错误").show();
            return;
        }else if (StringUtils.equals(addr,Cache.getProConfig(Const.BASE_SERVER_ADDR))){
            CommonUtil.alert(Alert.AlertType.WARNING,"未改变原有服务器地址！","请输入新的服务器地址!","警告").show();
            return;
        }

        Map<String, Object> map = BasicNetService.getInstance().testNetHandler(addr);
        if ((boolean)map.get("flag")){
            CommonUtil.alert(Alert.AlertType.INFORMATION,null,"连接成功!","提示").show();
            try {
                InitContext.updateProperties("BASE_SERVER_ADDR", addr);
            } catch (IOException e) {
                CommonUtil.alert(Alert.AlertType.WARNING,"更新配置文件失败！","连接成功!但是将服务器地址保存到配置文件时发生问题，" +
                        "建议再次点击\"更换地址\"按钮，以重试写入配置文件。错误代码："+e.getMessage(),"提示").show();
            }
        }else{
            CommonUtil.alert(Alert.AlertType.ERROR,"连接失败！","发生错误："+map.get("msg"),"错误").show();
        }
    }

    private void changeMainPassBtnHandler(){
        Dialog<Pair<String,String>> dialog=new Dialog<>();
        dialog.setTitle("修改主密码");
        dialog.setHeaderText("正在修改主密码");
        dialog.setGraphic(new ImageView(this.getClass().getResource("image/1.jpg").toString()));

        ButtonType changeBtnType=new ButtonType("修改", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(changeBtnType,ButtonType.CANCEL);

        GridPane grid=new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20,150,10,10));

        PasswordField oldPass=new PasswordField();
        oldPass.setPromptText("输入旧密码");
        PasswordField newPass=new PasswordField();
        newPass.setPromptText("输入新密码");

        grid.add(new Label("旧密码:"), 0, 0);
        grid.add(oldPass, 1, 0);
        grid.add(new Label("新密码:"), 0, 1);
        grid.add(newPass, 1, 1);

        Node lookupButton = dialog.getDialogPane().lookupButton(changeBtnType);
        lookupButton.setDisable(true);

        oldPass.textProperty().addListener((observable,oldValue,newValue)->{
            lookupButton.setDisable(newValue.trim().isEmpty());
        });

        dialog.getDialogPane().setContent(grid);

        Platform.runLater(()->oldPass.requestFocus());

        dialog.setResultConverter(dialogButton->{
            if(dialogButton==changeBtnType){
                return new Pair<>(oldPass.getText(),newPass.getText());
            }
            return null;
        });

        Optional<Pair<String, String>> result = dialog.showAndWait();
        result.ifPresent(consumer->{
            String oldp=consumer.getKey();
            String newp=consumer.getValue();

            if(StringUtils.isBlank(newp)||StringUtils.isBlank(oldp)){
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","新密码和旧密码都不能为空","错误").show();
                return;
            }else if(StringUtils.equals(oldp, newp)){
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","新密码和旧密码相同","错误").showAndWait();
                return;
            }else if(!SecurityController.getSecurityInstence().checkMainPass(oldp)){
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","旧密码输入错误","错误").showAndWait();
                return;
            }
            String newMainPass=SecurityController.getSecurityInstence().getKey(newp);
            String oldMainPass=Cache.getKey();
            try {
                List<PasswordItem> list = pd.getAllPasswordItem();
                //更新主密码
                if(cd.updateMainPass(SecurityController.getSecurityInstence().encryptionMain(newp))){
                    if(!list.isEmpty()){
                        for(PasswordItem pi:list){
                            try {
                                //首先解密
                                pi.setAccount(SecurityController.getSecurityInstence().AESdecrypt(pi.getAccount(), oldMainPass));
                                pi.setPasswordStr(SecurityController.getSecurityInstence().AESdecrypt(pi.getPasswordStr(), oldMainPass));
                                //用新密码加密
                                pi.setAccount(SecurityController.getSecurityInstence().AESencrypt(pi.getAccount(), newMainPass));
                                pi.setPasswordStr(SecurityController.getSecurityInstence().AESencrypt(pi.getPasswordStr(), newMainPass));
                            } catch (Exception ex) {
                            }
                            //pi.setModifyTime(CommonUtil.getTime());
                            Map<QueueType,String> map=new HashMap<>();
                            map.put(QueueType.PASSITEM,pi.getPassId());
                            Cache.addUpdateModifyTimeQueue(map);
                            //保存
                            pd.updatePasswordItemFromId(pi);
                        }
                        Cache.getOc().setMainPass(newMainPass);
                    }
                }
                //加密主密码
                String newMainPassStr= SecurityController.getSecurityInstence().encryptionMain(newp);
                new OnepassConfigDao().updateMainPass(newMainPassStr);
                if(Boolean.valueOf(Cache.getProConfig(Const.ACTIONCLOUD))){//已经激活云服务
                    if (StringUtils.isEmpty(Cache.getProConfig(Const.COLUDACCOUNT))){
                        throw new Exception("云账号为空！");
                    }
                        //更新配置信息中的云账号
                    String coludaccount = SecurityController.getSecurityInstence().decryptColudAccount(Cache.getProConfig(Const.COLUDACCOUNT),oldMainPass);
                    coludaccount=SecurityController.getSecurityInstence().encryptColudAccount(coludaccount,newMainPass);
                    /*String coludaccount=SecurityController.getSecurityInstence().AESdecrypt(Cache.getProConfig(Const.COLUDACCOUNT), oldMainPass);
                        coludaccount=SecurityController.getSecurityInstence().AESencrypt(coludaccount, newMainPass);*/

                        //更新配置文件
                        InitContext.updateProperties("COLUDACCOUNT", coludaccount);
                }
                Map<QueueType,String> queue=new HashMap<>();
                queue.put(QueueType.CONFIG,"");
                Cache.addUpdateModifyTimeQueue(queue);
                BackService.startUpdateModifyTimeService();
                CommonUtil.alert(Alert.AlertType.INFORMATION,"密码修改成功!","主密码修改后请使用新密码重新登录系统!","成功").showAndWait();
                preferencesDialogStage.close();
                start.initLoginLayout(false);
            } catch (SQLException ex) {
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","修改主密码时发生系统错误!"+ex.getMessage(),"错误").showAndWait();
            } catch (IOException ex) {
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","修改主密码时发生系统错误!读取数据文件发生异常!"+ex.getMessage(),"错误").showAndWait();
            }catch(ClassNotFoundException ex){
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","找不到数据库驱动!"+ex.getMessage(),"错误").showAndWait();
            } catch (Exception ex) {
                ex.printStackTrace();
                CommonUtil.alert(Alert.AlertType.ERROR,"修改失败","错误原因："+ex.getMessage(),"错误").showAndWait();
            }
        });
    }
    //保存常规设置
    private void saveChangGuiBtnHandler(){
        Boolean start = startAutoUpdate.selectedProperty().getValue();
        Boolean tuopan = minSysTuoPan.selectedProperty().getValue();
        Boolean close = closeMinWindowNoClose.selectedProperty().getValue();
        Boolean clear = autoClearPanel.selectedProperty().getValue();
        String autoClearTime = autoClearPanelTime.getSelectionModel().getSelectedItem();
        Boolean min = minningLock.selectedProperty().getValue();
        Boolean kongxian = kongXianLock.selectedProperty().getValue();
        String kongxiantime = kongXianLockTime.getSelectionModel().getSelectedItem();

        OnepassConfig oc=new OnepassConfig();
        oc.setStartAutoUpdate(String.valueOf(start));
        oc.setMinSysTuoPan(String.valueOf(tuopan));
        oc.setCloseMinWindowNoClose(String.valueOf(close));
        oc.setAutoClearPanel(String.valueOf(clear));
        oc.setAutoClearPanelTime(autoClearTime);
        oc.setMinningLock(String.valueOf(min));
        oc.setKongXianLock(String.valueOf(kongxian));
        oc.setKongXianLockTime(String.valueOf(kongxiantime));
        //oc.setModifyTime(CommonUtil.getTime());

        try{
            if(cd.saveChangGuiConfig(oc)){
                Map<QueueType,String> queue=new HashMap<>();
                queue.put(QueueType.CONFIG,"");
                Cache.addUpdateModifyTimeQueue(queue);
                BackService.startUpdateModifyTimeService();

                CommonUtil.alert(Alert.AlertType.INFORMATION,null,"配置信息保存成功,新的配置将在下次启动后生效！","成功").showAndWait();
            }else{
                CommonUtil.alert(Alert.AlertType.ERROR,null,"配置信息保存失败！","失败").showAndWait();
            }
        }catch(SQLException e){
            CommonUtil.alert(Alert.AlertType.ERROR,"保存失败","数据文件写入配置信息时发生异常！"+e.getMessage(),"失败").showAndWait();
        }catch(ClassNotFoundException e){
            CommonUtil.alert(Alert.AlertType.ERROR,"保存失败","找不到数据库驱动！"+e.getMessage(),"失败").showAndWait();
        }
    }
    private void initChangGuiConfig(Tab tab){
        autoClearPanelTime.setItems(FXCollections.observableArrayList("3","5","8","10","12","15","20","30"));
        kongXianLockTime.setItems(FXCollections.observableArrayList("3","5","10","15","20","30"));
        autoClearPanelTime.getSelectionModel().selectFirst();
        kongXianLockTime.getSelectionModel().selectFirst();
        autoClearPanel.setOnAction(e->{
            autoClearPanelTime.setDisable(!autoClearPanel.isSelected());
        });
        kongXianLock.setOnAction(e->{
            kongXianLockTime.setDisable(!kongXianLock.isSelected());
        });
        try{
            OnepassConfig onepassConfig=cd.getOnepassConfig();
            if(onepassConfig!=null){
                if(StringUtils.equals("true", onepassConfig.getStartAutoUpdate())){
                    startAutoUpdate.selectedProperty().setValue(true);
                }
                if(StringUtils.equals("true", onepassConfig.getMinSysTuoPan())){
                    minSysTuoPan.selectedProperty().setValue(true);
                }
                if(StringUtils.equals("true", onepassConfig.getCloseMinWindowNoClose())){
                    closeMinWindowNoClose.selectedProperty().setValue(true);
                }
                if(StringUtils.equals("true", onepassConfig.getAutoClearPanel())){
                    autoClearPanel.selectedProperty().setValue(true);
                    autoClearPanelTime.setDisable(false);
                }
                if(StringUtils.equals("true", onepassConfig.getMinningLock())){
                    minningLock.selectedProperty().setValue(true);
                }
                if(StringUtils.equals("true", onepassConfig.getKongXianLock())){
                    kongXianLock.selectedProperty().setValue(true);
                    kongXianLockTime.setDisable(false);
                }
                if(StringUtils.isNotBlank(onepassConfig.getAutoClearPanelTime())){
                    autoClearPanelTime.getSelectionModel().select(onepassConfig.getAutoClearPanelTime());
                }
                if(StringUtils.isNotBlank(onepassConfig.getKongXianLockTime())){
                    kongXianLockTime.getSelectionModel().select(onepassConfig.getKongXianLockTime());
                }

            }
        }catch(SQLException e){
            CommonUtil.alert(Alert.AlertType.ERROR,"初始化常规配置错误","从数据文件读取常规配置信息时发生异常！"+e.getMessage(),"错误").showAndWait();
        }catch(ClassNotFoundException e){
            CommonUtil.alert(Alert.AlertType.ERROR,"初始化常规配置错误","找不到数据库驱动！"+e.getMessage(),"错误").showAndWait();
        }
    }
    private void regColud(){
        String trim = coludAccountInput.getText().trim();

        String check= CommonUtil.checkCloudAccount(trim);
        if(StringUtils.isBlank(check)){
            try {
                Map<String, Object> result = BasicNetService.getInstance().regCheckColudAccount(trim);

                if((boolean)result.get("flag")){
                    topLabel.setText("已绑定账号:"+trim);
                    topLabel.setTextFill(Color.web("#008000"));
                    regHboxPanel.setDisable(true);

                    CommonUtil.alert(Alert.AlertType.INFORMATION,"注册成功!",
                            "从现在起onepass将会自动同步你的密码库至服务器,在新设备上登录该账号可以将服务器密码" +
                                    "库同步至本地.","成功").showAndWait();

                    //更新配置文件信息
                    InitContext.updateProperties("ACTIONCLOUD", "true");
                    InitContext.updateProperties("COLUDACCOUNT", SecurityController.getSecurityInstence().encryptColudAccount(trim,Cache.getKey()));
                    //写入默认时间服务器地址
                    InitContext.updateProperties("TIMESERVER","www.360.com");
                    //InitContext.init();//重新读取系统配置
                    //将所有数据的modifytime都使用授时服务器校验一次并执行同步
                    new CommonDao().initSyncData();
                    BackService.startUpdateModifyTimeService();
                }else{
                    CommonUtil.alert(Alert.AlertType.ERROR,"注册失败!",result.get("msg")+"","失败").showAndWait();
                   /* CommonUtil.alert(Alert.AlertType.ERROR,"注册失败!",new String(((String)result.get("msg")).getBytes(),
                            "utf-8"),"失败").showAndWait();*/
                }
            } catch (IOException ex) {
                CommonUtil.alert(Alert.AlertType.ERROR,"网络连接失败!",ex.getMessage()+"\n请确认你可以访问onepass" +
                        "官网服务器：http://www.onepass.vip","失败").showAndWait();
            } catch (Exception ex) {
                CommonUtil.alert(Alert.AlertType.ERROR,"注册失败!",ex.getMessage(),"失败").showAndWait();
            }
        }else{
            CommonUtil.alert(Alert.AlertType.ERROR,"输入有误!",check,"错误").showAndWait();
        }
    }
}
